package net.orange.architecture.db;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import net.orange.architecture.model.BaseValueObject;

/**
 * The base cache data access object. when the system access the data, it will
 * search in the memory first. If it can't be found, so will continue search in
 * database. While updating the data, system will update the relate data in
 * cache only.
 */
public abstract class PassiveCacheDao implements IObjectManager {

	private static Map<Object, BaseValueObject> cache = new HashMap<Object, BaseValueObject>();

	private IObjectManager target;

	/**
	 * @param target
	 *            The target.
	 */
	public PassiveCacheDao(IObjectManager target) {
		this.target = target;
	}

	/**
	 * @return Returns the target.
	 */
	public IObjectManager getTarget() {
		return target;
	}

	/**
	 * @param target
	 *            The target to set.
	 */
	public void setTarget(IObjectManager target) {
		this.target = target;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.orange.architecture.db.IBaseDao#getValueObjectClassName()
	 */
	public String getValueObjectClassName() {
		return target.getValueObjectClassName();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * net.orange.architecture.db.IBaseDao#setValueObjectClassName(java.lang
	 * .String)
	 */
	public void setValueObjectClassName(String valueObjectClassName)
			throws Exception {
		target.setValueObjectClassName(valueObjectClassName);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.orange.architecture.db.IBaseDao#list(net.orange.architecture.db.
	 * Conditions)
	 */
	public Collection list(Conditions cds) throws Exception {
		Collection r = target.list(cds);
		return r;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.orange.architecture.db.IBaseDao#list(net.orange.architecture.db.
	 * Conditions, net.orange.architecture.db.Orders)
	 */
	public Collection list(Conditions cds, Orders orders) throws Exception {
		Collection r = target.list(cds, orders);
		return r;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * net.orange.architecture.db.IBaseDao#list2(net.orange.architecture.db.
	 * ListConditions)
	 */
	public Collection list2(ListConditions cds) throws Exception {
		Collection r = target.list2(cds);
		return r;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.orange.architecture.db.IBaseDao#list(java.lang.String)
	 */
	public Collection list(String s) throws Exception {
		Collection r = target.list(s);
		return r;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.orange.architecture.db.IBaseDao#find(long)
	 */
	public BaseValueObject find(long id) throws Exception {
		BaseValueObject r = target.find(id);
		return r;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.orange.architecture.db.IBaseDao#find(java.lang.String,
	 * java.lang.String)
	 */
	public BaseValueObject find(String field, String code) throws Exception {
		BaseValueObject r = target.find(field, code);
		return r;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.orange.architecture.db.IBaseDao#find(net.orange.architecture.db.
	 * Conditions)
	 */
	public BaseValueObject find(Conditions cds) throws Exception {
		BaseValueObject r = target.find(cds);
		return r;
	}

	/*
	 * @see
	 * net.orange.architecture.db.IBaseDao#create(net.orange.architecture.vo
	 * .BaseValueObject)
	 */
	public boolean create(BaseValueObject b0) throws Exception {
		boolean r = target.create(b0);
		cache.put(getKey(b0), b0);
		return r;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * net.orange.architecture.db.IBaseDao#update(net.orange.architecture.vo
	 * .BaseValueObject)
	 */
	public boolean update(BaseValueObject b0) throws Exception {
		BaseValueObject e0 = find(b0.getPk());
		Object key = getKey(e0);

		boolean r = target.update(b0);

		cache.remove(key);
		cache.put(getKey(b0), b0);

		return r;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * net.orange.architecture.db.IBaseDao#createOrUpdate(net.orange.architecture
	 * .vo.BaseValueObject)
	 */
	public boolean createOrUpdate(BaseValueObject b0) throws Exception {
		BaseValueObject e0 = find(b0.getPk());
		Object key = getKey(e0);

		boolean r = target.createOrUpdate(b0);

		cache.remove(key);
		cache.put(getKey(b0), b0);

		return r;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * net.orange.architecture.db.IBaseDao#delete(net.orange.architecture.vo
	 * .BaseValueObject)
	 */
	public boolean delete(BaseValueObject b0) throws Exception {
		Object key = getKey(b0);

		boolean r = target.delete(b0);
		cache.remove(key);
		return r;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.orange.architecture.db.IBaseDao#delete(long)
	 */
	public boolean delete(long id) throws Exception {
		BaseValueObject e0 = find(id);
		Object key = getKey(e0);

		boolean r = target.delete(id);
		cache.remove(key);
		return r;
	}

	/**
	 * Get the key of the value objct.
	 * 
	 * @param b0
	 *            The value object;
	 * @return The key of the value object.
	 */
	protected abstract Object getKey(BaseValueObject b0);

	/**
	 * Load the object from database according the key.
	 * 
	 * @return the object.
	 */
	protected abstract BaseValueObject loadByKey(Object key);

	/**
	 * @param key
	 * @return
	 * @throws Exception
	 */
	public BaseValueObject findByKey(Object key) throws Exception {
		if (!cache.containsKey(key)) {
			BaseValueObject object = loadByKey(key);
			if (object != null)
				cache.put(key, object);
		}
		return cache.get(key);
	}
}
